import { IconPicture } from "@codexteam/icons"
import { make } from "../../utils/dom"
import { v4 as uuid } from "uuid"

/**
 * Enumeration representing the different states of the UI.
 */
const UiState = {
	/**
	 * The UI is in an empty state, with no image loaded or being uploaded.
	 */
	Empty: "empty",

	/**
	 * The UI is in an uploading state, indicating an image is currently being uploaded.
	 */
	Uploading: "uploading",

	/**
	 * The UI is in a filled state, with an image successfully loaded.
	 */
	Filled: "filled",
}
export default class Ui {
	/**
	 * @param ui - image tool Ui module
	 * @param ui.api - Editor.js API
	 * @param ui.config - user config
	 * @param ui.onSelectFile - callback for clicks on Select file button
	 * @param ui.readOnly - read-only mode flag
	 * @param ui.styleConfig - image config
	 */
	constructor({ api, config, onSelectFile, readOnly, styleConfig }) {
		this.api = api
		this.config = config
		this.onSelectFile = onSelectFile
		this.readOnly = readOnly
		this.styleConfig = styleConfig
		this.nodes = {
			wrapper: make("div", [this.CSS.baseClass, this.CSS.wrapper]),
			imageContainer: make("div", [this.CSS.imageContainer]),
			fileButton: this.createFileButton(),
			imageEl: undefined,
			imagePreloader: make("div", this.CSS.imagePreloader),
			caption: make("div", [this.CSS.input, this.CSS.caption], {
				contentEditable: !this.readOnly,
			}),
		}

		this.nodes.caption.dataset.placeholder = this.config.captionPlaceholder
		this.nodes.imageContainer.appendChild(this.nodes.imagePreloader)
		this.nodes.wrapper.appendChild(this.nodes.imageContainer)
		this.nodes.wrapper.appendChild(this.nodes.caption)
		this.nodes.wrapper.appendChild(this.nodes.fileButton)

		//  渲染初始化设置元素宽高样式
		this.nodes.imageContainer.style.width = styleConfig.width
		this.nodes.imageContainer.style.height = styleConfig.height

		//   创建调整大小的手柄数组
		this.resizeHandles = []

		//   给容器imageContainer添加 wrapper 类
		this.nodes.imageContainer.classList.add("image-tool__wrapper")

		//   添加点击事件监听器以显示调整大小的手柄
		this.nodes.imageContainer.addEventListener("click", (e) => {
			if (!this.readOnly) {
				e.stopPropagation()
				// 删除之前激活手柄
				if (Ui.activeImageContainer && Ui.activeImageContainer !== this.nodes.imageContainer) {
					const prevUi = this.findUiInstance(Ui.activeImageContainer)
					if (prevUi) {
						prevUi.hideResizeHandles()
					}
				}

				Ui.activeImageContainer = this.nodes.imageContainer
				this.createResizeHandles()
			}
		})

		//   添加文档点击事件监听器以隐藏调整大小的手柄
		document.addEventListener("click", (e) => {
			if (!this.nodes.imageContainer.contains(e.target)) {
				this.hideResizeHandles()
			}
		})
	}
	findUiInstance(container) {
		// 查找与容器元素关联的 UI 实例
		return container._uiInstance
	}

	//   创建调整大小的手柄方法
	createResizeHandles() {
		this.hideResizeHandles()
		const positions = ["top", "bottom", "left", "right", "top-left", "top-right", "bottom-left", "bottom-right"]
		this.resizeHandles = positions.map((pos) => {
			const handle = make("div", [`image-tool__resize-handle`, `image-tool__resize-handle--${pos}`])
			handle.addEventListener("mousedown", (e) => this.handleResizeStart(e, pos))
			return handle
		})
		this.resizeHandles.forEach((handle) => this.nodes.imageContainer.appendChild(handle))
		this.showResizeHandles()
		// 在容器上存储对 UI 实例的引用
		this.nodes.imageContainer._uiInstance = this
	}

	//   处理开始调整大小的事件方法
	handleResizeStart(e, direction) {
		e.stopPropagation()
		const startX = e.clientX
		const startY = e.clientY
		const startWidth = this.nodes.imageContainer.offsetWidth
		const startHeight = this.nodes.imageContainer.offsetHeight

		const handleResize = (e) => {
			let newWidth = startWidth
			let newHeight = startHeight

			if (direction.includes("right")) {
				newWidth = startWidth + (e.clientX - startX)
			} else if (direction.includes("left")) {
				newWidth = startWidth - (e.clientX - startX)
			}

			if (direction.includes("bottom")) {
				newHeight = startHeight + (e.clientY - startY)
			} else if (direction.includes("top")) {
				newHeight = startHeight - (e.clientY - startY)
			}

			this.nodes.imageContainer.style.width = `${newWidth}px`
			this.nodes.imageContainer.style.height = `${newHeight}px`
			// if (this.nodes.imageEl) {
			// 	this.nodes.imageEl.style.width = `${newWidth}px`
			// 	this.nodes.imageEl.style.height = `${newHeight}px`
			// }
		}

		const handleResizeEnd = () => {
			document.removeEventListener("mousemove", handleResize)
			document.removeEventListener("mouseup", handleResizeEnd)
		}

		document.addEventListener("mousemove", handleResize)
		document.addEventListener("mouseup", handleResizeEnd)
	}
	//   显示调整大小的手柄方法
	showResizeHandles() {
		this.nodes.imageContainer.style.border = "1.5px solid #3d3d3d"
		this.resizeHandles.forEach((handle) => (handle.style.display = "block"))
	}

	//   隐藏调整大小的手柄方法
	hideResizeHandles() {
		this.nodes.imageContainer.style.border = ""
		// this.resizeHandles.forEach((handle) => (handle.style.display = "none"))
		if (this.resizeHandles.length > 0) {
			this.resizeHandles.forEach((handle) => this.nodes.imageContainer.removeChild(handle))
			this.resizeHandles = []
		}
	}
	/**
	 * Apply visual representation of activated tune
	 * @param tuneName - one of available tunes {@link Tunes.tunes}
	 * @param status - true for enable, false for disable
	 */
	applyTune(tuneName, status) {
		const alignArr = ["alignLeft", "alignCenter", "alignRight"]
		// 将对齐相关的样式都置为false 再重新设置
		if (alignArr.includes(tuneName)) {
			alignArr.forEach((alignment) => {
				this.nodes.wrapper.classList.remove(`${this.CSS.wrapper}--${alignment}`)
			})
		}
		requestAnimationFrame(() => {
			this.nodes.wrapper.classList.toggle(`${this.CSS.wrapper}--${tuneName}`, status)
		})
	}
	/**
	 * Renders tool UI
	 * @param toolData - saved tool data
	 */
	render(toolData) {
		if (toolData.file === undefined || Object.keys(toolData.file).length === 0) {
			this.toggleStatus(UiState.Empty)
		} else {
			this.toggleStatus(UiState.Uploading)
		}

		return this.nodes.wrapper
	}
	/**
	 * Shows uploading preloader
	 * @param src - preview source
	 */
	showPreloader(src) {
		this.nodes.imagePreloader.style.backgroundImage = `url(${src})`

		this.toggleStatus(UiState.Uploading)
	}
	/**
	 * Hide uploading preloader
	 */
	hidePreloader() {
		this.nodes.imagePreloader.style.backgroundImage = ""
		this.toggleStatus(UiState.Empty)
	}
	/**
	 * Shows an image
	 * @param url - image source
	 */
	fillImage(url) {
		/**
		 * Check for a source extension to compose element correctly: video tag for mp4, img — for others
		 */
		const tag = /\.mp4$/.test(url) ? "VIDEO" : "IMG"

		const attributes = {
			src: url,
		}

		/**
		 * We use eventName variable because IMG and VIDEO tags have different event to be called on source load
		 * - IMG: load
		 * - VIDEO: loadeddata
		 */
		let eventName = "load"

		/**
		 * Update attributes and eventName if source is a mp4 video
		 */
		if (tag === "VIDEO") {
			/**
			 * Add attributes for playing muted mp4 as a gif
			 */
			attributes.autoplay = true
			attributes.loop = true
			attributes.muted = true
			attributes.playsinline = true

			/**
			 * Change event to be listened
			 */
			eventName = "loadeddata"
		}
		/**
		 * Compose tag with defined attributes
		 */
		this.nodes.imageEl = make(tag, this.CSS.imageEl, attributes)
		// 给图片容器添加自定义数据属性作为图片标识
		this.nodes.imageEl.id = uuid()
		/**
		 * Add load event listener
		 */
		this.nodes.imageEl.addEventListener(eventName, () => {
			this.toggleStatus(UiState.Filled)
			//   确保图片填充其容器
			this.nodes.imageEl.style.width = "100%"
			this.nodes.imageEl.style.height = "100%"
			/**
			 * Preloader does not exists on first rendering with presaved data
			 */
			if (this.nodes.imagePreloader !== undefined) {
				this.nodes.imagePreloader.style.backgroundImage = ""
			}
		})

		this.nodes.imageContainer.appendChild(this.nodes.imageEl)
	}
	/**
	 * Shows caption input
	 * @param text - caption content text
	 */
	fillCaption(text) {
		if (this.nodes.caption !== undefined) {
			this.nodes.caption.innerHTML = text
		}
	}
	/**
	 * CSS classes
	 */
	get CSS() {
		return {
			baseClass: this.api.styles.block,
			loading: this.api.styles.loader,
			input: this.api.styles.input,
			button: this.api.styles.button,

			/**
			 * Tool's classes
			 */
			wrapper: "image-tool",
			imageContainer: "image-tool__image",
			imagePreloader: "image-tool__image-preloader",
			imageEl: "image-tool__image-picture",
			caption: "image-tool__caption",
		}
	}
	/**
	 * Creates upload-file button
	 */
	createFileButton() {
		const button = make("div", [this.CSS.button])

		button.innerHTML = this.config.buttonContent ?? `${IconPicture} ${this.api.i18n.t("Select an Image")}`

		button.addEventListener("click", () => {
			this.onSelectFile()
		})

		return button
	}

	/**
	 * Changes UI status
	 * @param status - see {@link Ui.status} constants
	 */
	toggleStatus(status) {
		for (const statusType in UiState) {
			if (Object.prototype.hasOwnProperty.call(UiState, statusType)) {
				this.nodes.wrapper.classList.toggle(`${this.CSS.wrapper}--${UiState[statusType]}`, status === UiState[statusType])
			}
		}
	}
}

